// for Emacs -*- c++ -*-

#ifndef _EVENTPROCESSORIMP_H_
#define _EVENTPROCESSORIMP_H_

#include <map>
#include <vector>
#include <pthread.h>

#include "MultiMessageQueue.h"
#include "EventProcessor.h"

/** Base class to implement all the event processors.
    
    The class uses a MultiMessageQueue to get messages, and calls functions that
    can process the messages. The implementation is generic so extra functionality 
    can be added for actual event processors.

    The EventProcessor owns the MultiMessageQueue and just makes it available
    to writtes so messages can be sent.

    The class keeps a mapping of integer types to methods that can process that 
    message type. 

    To add capabilities to process a new message type, a method has to be written 
    that converts the basic message into the correct message type. 

    WARNING1: While the datastructures to manage the event processor
    data are protected by a mutex, the activity of the message
    processing functions is not protected at all. For this reason, by default,
    only one thread can be started to process the messages (forksRemaining=1).
    In the derived class, if forksRemaining is increased, mutexes inside
    the message processing functions should be used as needed. The existing mutex,
    call mutex can be used or other, more refined mutexes should be defined.

    WARNING2: The event processors should be created on the heap and
    destroied explicitly. The call to ForkAndSpin() is nonblocking
    and will return almost immediately.
    
    Instantiating this class directly does not make much sense. It
    should be derived from.

*/


class EventProcessorImp {
public:
  // type of methods that can process messages
  typedef void (*msgProcessor)(EventProcessorImp&, Message&);

#include "EventProcessorImpPrivate.h"

protected:
  
  // data for debuging purposes
  bool debug;
  const char *dbgMsg;
  
  // Processsor for the kill messages
  // When this method is called, it should be assumend that 
  // the object cannot be accessed further (except the destructor)
  static void processDieMessage(EventProcessorImp &_obj, Message &in);
  
  // some event processors need to be cloned so that multiple threads work in parallel
  // this has to be done carefully so by default no event processor is forkable
  int forksRemaining; // set to 1 so only one thread runs
  
  // interface object that can be used to communicate with this event processor
  EventProcessor myInterface;
  

  // general purpose mutex to be used in this class. More refined mutexes can be defined 
  // and used in derived classes
  pthread_mutex_t mutex;
  
  
  // register a processor for a new type of message
  // the Type is the numeric type associated with the type of message
  // proc is the method dealing with this type of message
  // Priority is the priority of this type (default highest)
  // The constructor of any derived class that has clear functionality 
  // has to call this method for all the messages tha need to be processed
  // Only designers of Event Processors should call this otherwise it can be quite dangerous
  // If the method is called multiple times for the same type, the old info is overwritten
  // this allows "overloading" of the Die behavior
  void RegisterMessageProcessor(int Type, msgProcessor Proc, int Priority=1);

  // set the maximum number of threads that an EventProessor supports
  // this does not start that many threads, it just sets the limit
  void SetMaxThreads(int max){ forksRemaining=max; }

private:
  // protect the copy constructor and the asignment operators to ensure
  // they are never used
  EventProcessorImp(const EventProcessorImp&);
  EventProcessorImp& operator = (const EventProcessorImp&);
  
public:
  // constructor
  // if debug is true, debugging messages are printed (contain string dbgMsg)
  EventProcessorImp(bool _debug = false, const char *_dbgMsg = NULL);

  // This method is called in the thread running the writer
  // All the other methods in EventProcessor run in a separate thread
  // The message results in putting the message in the message queue
  // Thread safety is ensured by the queue so there is no problem with simultaneous execution
  void ProcessMessage(Message& msg);
 

  // this method creates another thread running the main event processing loop
  // if the return false, than no thread was started
  // since the maximum number of threads allowed by this event is already reached
  // WARNING: this method only starts one thread, not all the allowed threads
  // it has to be executed repeteadly to start multiple threads
  bool ForkAndSpin(int node=NUMA_ALL_NODES); // the default is defined

  // When this functin is called, the thread calling it blocks until the event 
  // processor gets the Die message. This is useful to write main programs that 
  // wait for the whole thing to finish
  void WaitForProcessorDeath(void);

	// method to commit suicide. This should be called if the event processor wants to kill itself
	void Seppuku();

  // destructor 
  virtual ~EventProcessorImp();
};


#endif // _EVENTPROCESSORIMP_H_
